package com.szh.mysobproject.viewmodel.app

import androidx.lifecycle.LiveData
import androidx.lifecycle.LiveDataScope
import androidx.lifecycle.liveData
import com.szh.mysobproject.execption.NotLoginException
import com.szh.mysobproject.execption.ServiceException
import com.szh.mysobproject.http.model.User
import com.szh.mysobproject.http.response.model.WallpaperBean
import com.szh.mysobproject.manager.UserManager
import com.szh.mysobproject.model.ApiResponse
import com.szh.mysobproject.util.lowercaseMd5
import com.szh.mysobproject.model.AppUpdateInfo
import com.szh.mysobproject.model.MourningCalendar
import com.szh.mysobproject.util.toJson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import timber.log.Timber
import java.io.File

object Repository {

    private val cachePhotoIdList = arrayListOf<WallpaperBean.Res.Vertical>()

    /**
     * 获取摸鱼标签
     */
    fun loadTopicList() = liveData(Dispatchers.IO) {
        launchAndGetData {
            FishNetwork.loadTopicList()
        }
    }

    /**
     * 查询用户头像
     */
    fun queryUserAvatar(account: String) = liveData(Dispatchers.IO) {
        val result = try {
            coroutineScope {
                val result = UserNetwork.queryUserAvatar(account)
                Timber.d("result is $result")
                if (result.isSuccess()) result.getData()
                else ""
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            ""
        }
        emit(result)
    }

    /**
     * 登录
     */
    suspend fun login(userAccount: String, password: String, captcha: String) = try {
        val user = User(userAccount, password.lowercaseMd5)
        val result = UserNetwork.login(captcha, user)
        if (result.isSuccess()) {
            val userBasicInfo = checkToken()
            // 将基本信息缓存到本地
            UserManager.saveUserBasicInfo(userBasicInfo)
            UserManager.setupAutoLogin(userBasicInfo != null)
            userBasicInfo ?: throw NotLoginException()
        } else throw ServiceException()
    } catch (t: Throwable) {
        t.printStackTrace()
        UserManager.setupAutoLogin(false)
        null
    }

    /**
     * 检查token
     */
    suspend fun checkToken() = try {
        val result = UserNetwork.checkToken()
        if (result.isSuccess()) {
            val userBasicInfo = result.getData()
            UserManager.saveUserBasicInfo(userBasicInfo)
            UserManager.setupAutoLogin(true)
            userBasicInfo
        } else throw ServiceException()
    } catch (t: Throwable) {
        t.printStackTrace()
        UserManager.saveUserBasicInfo(null)
        UserManager.setupAutoLogin(false)
        null
    }

    /**
     * 检查更新
     */
    fun checkAppUpdate(): LiveData<Result<AppUpdateInfo>> = liveData(Dispatchers.IO) {
        launchAndGetData {
            AppNetWork.checkAppUpdate()
        }
    }

    /**
     * 获取哀悼日历
     */
    fun getMourningCalendar(): LiveData<Result<List<MourningCalendar>>> = liveData(Dispatchers.IO) {
        launchAndGetData {
            AppNetWork.getMourningCalendar()
        }
    }

    /**
     * 点赞
     */
    fun dynamicLikes(momentId: String) = liveData(Dispatchers.IO) {
        launchAndGetMsg {
            FishNetwork.dynamicLikes(momentId)
        }
    }

    /**
     * 获取动态详情
     */
    fun loadFishDetailById(momentId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            FishNetwork.loadFishDetailById(momentId)
        }
    }

    /**
     * 发表评论
     */
    fun postComment(momentComment: Map<String, Any?>, isReply: Boolean) = liveData(Dispatchers.IO) {
        launchAndGetData {
            if (isReply) FishNetwork.replyComment(momentComment)
            else FishNetwork.postComment(momentComment)
        }
    }

    /**
     * 退出登录
     */
    fun logout() = liveData(Dispatchers.IO) {
        val result = try {
            coroutineScope {
                val result = UserNetwork.logout()
                Timber.d("result is $result")
                System.currentTimeMillis()
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            System.currentTimeMillis()
        }
        emit(result)
    }

    /**
     * 检查是否领取过津贴
     */
    fun checkAllowance() = liveData(Dispatchers.IO) {
        val result = try {
            coroutineScope {
                val result = UserNetwork.checkAllowance()
                Timber.d("result is $result")
                when (result.getCode()) {
                    // 未领取VIP津贴
                    11129 -> Result.success(false)
                    // 已经领取了VIP津贴
                    11128 -> Result.success(true)
                    else -> Result.failure(ServiceException(result.getMessage()))
                }
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            Result.failure(t)
        }
        emit(result)
    }

    /**
     * vip每月领取津贴
     */
    fun getAllowance() = liveData(Dispatchers.IO) {
        val result = try {
            coroutineScope {
                val result = UserNetwork.getAllowance()
                Timber.d("result is $result")
                when (result.getCode()) {
                    // 未领取VIP津贴
                    11129 -> Result.success(false)
                    // 已经领取了VIP津贴
                    11128 -> Result.success(true)
                    else -> Result.failure(ServiceException(result.getMessage()))
                }
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            Result.failure(t)
        }
        emit(result)
    }

    /**
     * 查询用户信息
     */
    fun queryUserInfo() = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.queryUserInfo()
        }
    }

    /**
     * 获取用户信息
     */

    fun getUserInfo(userId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.getUserInfo(userId)
        }
    }

    /**
     * 查询自己与指定用户的关注关系
     */
    fun followState(userId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.followState(userId)
        }
    }

    /**
     * 关注用户
     */
    fun followUser(userId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.followUser(userId)
        }
    }

    /**
     * 取消关注用户
     */
    fun unFollowUser(userId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.unFollowUser(userId)
        }
    }

    /**
     * 当前用户个人成就查询
     */

    fun getAchievement() = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.getAchievement()
        }
    }

    /**
     * 指定用户个人成就
     */
    fun getAchievement(userId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.getAchievement(userId)
        }
    }

    /**
     * 获取VIP用户列表
     */
    fun getVipUserList() = liveData(Dispatchers.IO) {
        launchAndGetData {
            UserNetwork.getVipUserList()
        }
    }

    /**
     * 获取未读消息
     */
    fun getUnReadMsgCount() = liveData(Dispatchers.IO) {
        launchAndGetData { MsgNetwork.getUnReadMsgCount() }
    }

    /**
     * 已读摸鱼消息
     */
    fun readMomentMsg(msgId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            MsgNetwork.readMomentMsg(msgId)
        }
    }

    /**
     * 已读@我的消息
     */
    fun readAtMeMsg(msgId: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            MsgNetwork.readAtMeMsg(msgId)
        }
    }

    /**
     * 已读问答消息
     */
    fun readQaMsg(msgID: String) = liveData(Dispatchers.IO) {
        launchAndGetData {
            MsgNetwork.readQaMsg(msgID)
        }
    }

    /**
     * 全部已读
     */
    fun readAllMsg() = liveData(Dispatchers.IO) {
        launchAndGetMsg {
            MsgNetwork.readAllMsg()
        }
    }

    /**
     * 获取壁纸轮播图
     */
    fun loadWallpaperBannerList() = liveData(Dispatchers.IO) {
        val result = try {
            coroutineScope {
                val result = PhotoNetwork.loadWallpaperBannerList()
                Timber.d("result is $result")
                if ("0" == result.errno) Result.success(result.data)
                else Result.failure(ServiceException())
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            Result.failure(t)
        }
        emit(result)
    }

    /**
     * 上传图片
     */
    suspend fun uploadFishImage(imageFile: File): String? {
        return try {
            val fileName = imageFile.name
            Timber.d("===> fileName is $fileName")
            val requestBody = RequestBody.create("image/png".toMediaType(), imageFile)
            val part = MultipartBody.Part.createFormData("image", fileName, requestBody)
            val result = FishNetwork.uploadFishImage(part)
            Timber.d("result is ${result.toJson()}")
            // 此处不能返回 Result<T> ，详见：https://github.com/mockk/mockk/issues/443
            // Result getOrNull give ClassCastException：https://stackoverflow.com/questions/68016267/result-getornull-give-classcastexception
            if (result.isSuccess()) result.getData()
            else null
        } catch (t: Throwable) {
            t.printStackTrace()
            null
        }
    }

    /**
     * 发布动态
     */
    fun putFish(moment: Map<String, Any?>) = liveData(Dispatchers.IO) {
        launchAndGetData { FishNetwork.putFish(moment) }
    }

    private suspend inline fun <reified T> LiveDataScope<Result<T>>.launchAndGetData(crossinline action: suspend () -> ApiResponse<T>) {
        launchAndGet(action = action, onSuccess = { it.getData() })
    }

    private suspend inline fun LiveDataScope<Result<Any>>.launchAndGetMsg(crossinline action: suspend () -> ApiResponse<Any>) {
        launchAndGet(action = action, onSuccess = { it.getMessage() })
    }

    private suspend inline fun <reified T> LiveDataScope<Result<T>>.launchAndGet(
        crossinline action: suspend () -> ApiResponse<T>,
        crossinline onSuccess: (ApiResponse<T>) -> T
    ) {
        val result = try {
            coroutineScope {
                val result = action.invoke()
                Timber.d("result is $result")
                if (result.isSuccess()) Result.success(onSuccess.invoke(result))
                else Result.failure(ServiceException(result.getMessage()))
            }
        } catch (t: Throwable) {
            t.printStackTrace()
            Result.failure(t)
        }

        emit(result)
    }

    fun setPhotoIdList(photoIdList: List<WallpaperBean.Res.Vertical>) {
        if (photoIdList !== cachePhotoIdList) {
            cachePhotoIdList.clear()
            if (photoIdList.isNullOrEmpty().not()) {
                cachePhotoIdList.addAll(photoIdList)
            }
        } else {
            if (photoIdList.isNullOrEmpty().not()) {
                val newList = photoIdList.toList()
                cachePhotoIdList.clear()
                cachePhotoIdList.addAll(newList)
            } else {
                cachePhotoIdList.clear()
            }
        }
    }

    fun getPhotoList() = cachePhotoIdList.toList()

}